%{ 
#include <string.h>
#include "scanner.h"
#include "debug.h"

static int first_time = 1;
struct cminus_token t;
int line_no = 0;

struct cminus_token token_buffer[MAX_RA_TOKEN];
static int front = 0;
static int rear = 0;

static int buffer_is_not_empty(int front, int rear);
static int buffer_is_not_full(int front, int rear);
static int get_cur_token_num(int front, int rear);
%}

digit       [0-9]
number      {digit}+
letter      [a-zA-Z]
identifier  {letter}+
newline     \n
whitespace  [ \t]+

%%
"int"          {return INT;}
"else"         {return ELSE;}
"void"         {return VOID;}
"if"           {return IF;}
"while"        {return WHILE;}
"return"       {return RETURN;}
"write"        {return WRITE;}
"read"         {return READ;}

"="            {return ASSIGN;}
"+"            {return PLUS;}
"-"            {return MINUS;}
"*"            {return TIMES;}
"/"            {return DIV;}
"<"            {return LT;}
">"            {return GT;}
"<="           {return NGT;}
">="           {return NLT;}
"=="           {return EQ;}
"!="           {return NEQ;}

"("            {return LPARAN;}
")"            {return RPARAN;}
"{"            {return LBRACE;}
"}"            {return RBRACE;}
"["            {return LSQUARE;}
"]"            {return RSQUARE;}
","            {return COMMA;}
";"            {return SEMI;}

{number}       {return NUM;}
{identifier}   {return ID;}
{newline}      {line_no++;}
{whitespace}   {/* skip whitespace */}
%%

struct cminus_token get_token()
{
   struct cminus_token cur_token;

   if (first_time)
   {
      first_time = 0;
      line_no ++;
      yyin = input_fp;
   }

   memset((void *)&cur_token, 0, sizeof(struct cminus_token));

   /*buffer is not empty, get from buffer*/
   if (buffer_is_not_empty(front, rear))
   {
      cur_token = token_buffer[rear];
      rear = (rear + 1) % MAX_RA_TOKEN;
   }
   else
   {
      cur_token.type = yylex();
      strncpy(cur_token.name, yytext, MAX_NAME_SZ);
   }

   return cur_token;
}

int virtual_get_token(int num)
{
   int i = 0;
   int cur_token_num = 0;
   int need_read_num = 0;
   struct cminus_token temp_token;

   if (first_time)
   {
      first_time = 0;
      line_no ++;
      yyin = input_fp;
   }

   cur_token_num = get_cur_token_num(front, rear);
   if (cur_token_num >= num)
   {
      return rear;
   }

   need_read_num = num - cur_token_num;

   for (i = 0; i < need_read_num; i++)
   {
   
      temp_token.type = yylex();
      strncpy(temp_token.name, yytext, MAX_NAME_SZ);

      if (buffer_is_not_full(front, rear))
      {
         token_buffer[front] = temp_token;
         front = (front + 1) % MAX_RA_TOKEN;
      }
      else
      {
         __ERROR_MSG("token read ahead buffer is full\n");
         exit(-1);
      }
   }

   return rear;
}

static int buffer_is_not_empty(int front, int rear)
{
   return (front != rear);
}

static int buffer_is_not_full(int front, int rear)
{
   int temp = 0;

   temp = (front + 1) % MAX_RA_TOKEN;
   return (temp != rear);
}

static int get_cur_token_num(int front, int rear)
{
   int temp = 0;
   temp = front -rear;

   if (temp < 0)
   {
      return (temp + MAX_RA_TOKEN);
   }
   else
   {
      return temp;
   }
}

int yywrap()
{
   return 1;
}
